import { readdirSync, statSync } from 'fs'
import { join } from 'path'
import { DynamicModule, Module, ValidationPipe } from '@nestjs/common'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core'
import { TypeOrmModule } from '@nestjs/typeorm'
import { ExceptionsFilter } from '@/common/filters'
import { JwtGuard } from '@/common/guards'
import { ResponseInterceptor, TransformEmptyStringInterceptor } from '@/common/interceptors'
import { AppController } from './app.controller'
import { AppService } from './app.service'

const PASS_FILE = ['invitation']
function loadModules(): DynamicModule[] {
  const modulesDir = join(__dirname, 'modules')
  const filterDirs = readdirSync(modulesDir).filter((file) => {
    if (PASS_FILE.includes(file)) {
      return false
    }
    const full = join(modulesDir, file)
    return statSync(full).isDirectory()
  })
  // console.log('[ filterDirs ] >', filterDirs)

  const requires = filterDirs.map((dir) => {
    // 约定每个模块有 xxx.module.ts
    const modulePath = join(__dirname, 'modules', dir, `${dir}.module`)
    // 引入模块文件
    const moduleExports = require(modulePath)
    // 连字符转大驼峰（如 detail-page → DetailPage）
    const kebabToCamel = (str: string) => {
      return str
        .split('-')
        .map(word => word.charAt(0).toUpperCase() + word.slice(1))
        .join('')
    }

    const moduleClassName = `${kebabToCamel(dir)}Module`
    // 提取命名导出的模块类（如 ActivityModule）
    const moduleClass = moduleExports[moduleClassName]
    if (!moduleClass) {
      throw new Error(`模块 ${dir} 未找到导出的模块类（${moduleClassName}）`)
    }
    return moduleClass
  })
  return requires
}

function loadEnvFile() {
  // 指定要加载的环境文件,前面的文件会覆盖前面的同名变量
  // 这里到生产启动一定会走 default，看看有什么办法处理，因为用的是cross-env指令指定的环境
  switch (process.env.NODE_ENV) {
    case 'production':
      return ['.env.production']
    case 'test':
      return ['.env.test']
    default:
      return ['.env.local', '.env.test', '.env.production']
  }
}
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true, // 使配置模块在整个应用程序中全局可用
      envFilePath: loadEnvFile(),
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        type: 'mysql',
        host: configService.get<string>('DATABASE_URL'),
        port: Number(configService.get<number>('DATABASE_PORT')),
        username: configService.get<string>('DATABASE_USERNAME'),
        password: configService.get<string>('DATABASE_PASSWORD'),
        database: 'douxian',
        // entities: [`${__dirname}/**/*.entity{.ts,.js}`],
        autoLoadEntities: true, // 自动加载forFeature的实体，上面的entities已经做了全部加载，开不开都一样
        // synchronize: !process.env.NODE_ENV,
        synchronize: true, // 是否自动同步数据库表结构，生产建议关闭
        migrations: [`${__dirname}/migrations/*.{ts,js}`],
        logging: true, // 开启日志
        logger: 'debug', // 日志类型
        extra: {
          connectionLimit: 10, // 连接池大小
        },
        retryAttempts: 1,
      }),
    }),
    // RedisModule.forRoot({
    //   type: 'single',
    //   url: 'redis://localhost:6379',
    // }),
    ...loadModules(),
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_PIPE,
      useFactory: () =>
        new ValidationPipe({
          transform: true, // 自动将请求参数转换为对应的 DTO 类型（如 string -> number）
          whitelist: true, // 忽略 DTO 中未定义的字段
          skipUndefinedProperties: true, // 忽略实体未定义字段
          forbidNonWhitelisted: false, // 不报错，直接丢弃多余字段（true 时会抛异常）
          skipMissingProperties: true, // 忽略 undefined 字段
          skipNullProperties: true, // 忽略 null 字段
          transformOptions: {
            enableImplicitConversion: false, // 启用隐式类型转换（自动把 传参变成 DTO 对应类型，传 'false' 会变成有字符串，变成 true ）
          },
        }),
    },
    {
      provide: APP_FILTER,
      useClass: ExceptionsFilter, // 依赖注入方式注册的全局异常过滤器
    },
    /**
     * 针对某个 controller 可以使用
     * @UseInterceptors(RequestQueueInterceptor)
     */
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor, // 依赖注入方式注册的全局响应拦截器
    },
    {
      provide: APP_INTERCEPTOR,
      useClass: TransformEmptyStringInterceptor,
    },
    // {
    //   provide: APP_INTERCEPTOR,
    //   useClass: RequestQueueInterceptor,
    // },
    {
      provide: APP_GUARD,
      useClass: JwtGuard,
    },
  ],
})
export class AppModule {
  // 整个项目注入 TypeOrmModule
  // constructor(
  // private dataSource: DataSource,
  // private configService: ConfigService,
  // ) {}
}
